package com.huike.clues.utils.easyExcel;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.huike.clues.domain.dto.ImportResultDTO;
import com.huike.clues.domain.vo.TbClueExcelVo;
import com.huike.clues.service.ITbClueService;

/**
 * EasyExcel监听器，用于解析数据并执行操作
 * 需求: 将所有数据都存入到数据库中即可
 * 如何实现:
 * 		   1) 我们应该在这个这个监听器里调用service或mapper来执行insert操作
 * 		   2) 将成功条数或失败条数返回给前端
 * 难点:
 * 		第一个难点: 我们要执行数据库的插入操作那么我们的监听器里面肯定要拿到对应的service或mapper对象
 * 	这时我们可能会想到用@Autowired自动注入，但是如果要注入一个service或mapper那么首先我们这个监听器类就应该被添加到IOC容器中，否则无法进行@Autowired，接口无法作为bean加入到IOC容器，所以这条方法行不通。
 * 	那如何拿到这个service或mapper呢？ 我们可以通过Controller层去拿，利用有参构造方法传入到每次new的监听器里。 因为Controller层能进行@Autowired，那么首先在Controller层注入一个我们需要的Service对象
 * 	然后在监听器里面我们还需要再创建一个带参构造方法，在这个构造方法里将Service指向成员属性的Service。
 * 		第二个难点: 通过阅读接口文档，我们需要返回 导入成功多少条，导入失败多少条 所以还需要构建一个实体类(ImportResultDTO)用来接收本次成功多少条失败多少条。
 * 	在invoke方法这里又出现问题了，因为我们的事件是单条插入的，每次只能知道这条数据有没有成功，如果说最后所有数据一次性导入还好说只要最终判断一下就好了，这里我们每次执行的时候都只能知道这条数据有没有后成功
 * 	但是怎么给前端返回最终成功多少条，失败多少条呢？这里可以借用享元的思想
 * 	如果我们在监听器里创建一个ImportResultDTO，而后续所有的添加操作都返回本次操作的ImportResultDTO，那么我们只要最终返回监听器里的ImportResultDTO不就可以完成最终方案的实现了呢？
 * 	所以我们还需要做的修改是在controller层将监听器对应的全局ImportResultDTO返回即可。
 */
public class ExcelListener extends AnalysisEventListener<TbClueExcelVo> {

	/**
	 * 利用构造方法获取对应的service
	 */
	public ITbClueService clueService;

	/** 构建一个全局的ImportResultDTO变量，用来返回最终成功和失败的线索数 */
	private ImportResultDTO resultDTO;

	/**
	 * 提供带参构造方法，在这里需要通过构造方法的方式获取对应的service层
	 * 谁调用这个监听器谁提供需要的service
	 * @param clueService
	 */
	public ExcelListener(ITbClueService clueService) {
		this.clueService = clueService;
		this.resultDTO = new ImportResultDTO();
	}

	/**
	 * 每解析一行数据都要执行一次
	 * 每条都执行一次插入操作
	 * @param data
	 * @param context
	 */
	@Override
	public void invoke(TbClueExcelVo data, AnalysisContext context) {
		ImportResultDTO addTbClue = clueService.importCluesData(data);  //线索的上传
		resultDTO.addAll(addTbClue);
	}

	/**
	 * 当所有数据都解析完成后会执行
	 * @param context
	 */
	@Override
	public void doAfterAllAnalysed(AnalysisContext context) {
		//由于在单条执行的事件里已经进行了数据的入库
		//在所有数据都插入完成后就不用再进行插入了,所以这个方法体内容可以省略不写
	}

	/**
	 * 返回结果集对象
	 * @return
	 */
	public ImportResultDTO getResult(){
		return resultDTO;
	}

}